package com.onpositive.datamap.item;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.onpositive.datamap.IDataPropertyValue;
import com.onpositive.datamap.core.IDataObject;
import com.onpositive.datamap.core.IDataProperty;
import com.onpositive.datamap.core.IImageObject;
import com.onpositive.datamap.core.ITextSection;
import com.onpositive.datamap.core.ITypedReference;
import com.onpositive.datamap.core.IVideoObject;
import com.onpositive.datamap.core.impl.AbstractDataProperty;
import com.onpositive.datamap.core.impl.LinkImageObject;
import com.onpositive.datamap.values.impl.TextSectionModel;
import com.onpositive.picture.utils.YoutubeFeed;
import com.onpositive.semantic.model.api.property.IHasPropertyProvider;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.semantic.model.api.property.IPropertyProvider;
import com.onpositive.semantic.model.api.property.PropertyAccess;

public class SingleDataObject implements IDataObject, IPropertyProvider,IHasPropertyProvider {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	protected IImageObject[] images;
	protected IImageObject preview;
	protected IImageObject mainImage;
	protected String caption;
	protected String uid;
	protected String textSection;
	protected boolean primary;
	MapDataAccessor accessor;
	
	protected SingleDataObject(){
		
	}

	public SingleDataObject(IDataObject o) {
		accessor = new MapDataAccessor(){
			@Override
			public void setValue(IDataObject obj, AbstractDataProperty p,
					Object value) {
				super.setValue(obj, p, value);
				postSet(obj,p,value);
			}
		};
		this.textSection = o.getTextContentAsString();
		this.images = convert(o.getGalleryImages());
		this.preview = convert(o.getPreviewImage());
		this.mainImage = convert(o.getPrimaryImage());
		this.caption = o.getCaption();
		this.uid = o.getUID();
		this.primary = o.isPrimaryObject();
		IDataPropertyValue[] properties2 = o.getProperties();
		IDataProperty[] p=new IDataProperty[properties2.length];
		int a=0;
		for (IDataPropertyValue q : properties2) {
			if (q==null){
				continue;
			}
			IDataPropertyValue clone = q.clone(accessor);			
			accessor.setValue(this, (AbstractDataProperty) clone.getProperty(), clone);
			p[a++]=clone.getProperty();
		}
		
	}

	protected void postSet(IDataObject obj, AbstractDataProperty p, Object value) {
		
	}

	public static SingleDataObject from(byte[] byteArray) {
		try{
		ByteArrayInputStream m = new ByteArrayInputStream(byteArray);
		Hessian2Input hessian2Input = new Hessian2Input(new GZIPInputStream(m));
		SingleDataObject readObject = (SingleDataObject) hessian2Input.readObject();
		return readObject;
		}catch (Exception e) {
			e.printStackTrace();
			throw new IllegalStateException();
		}
	}
	
	@Override
	public String getTextContentAsString() {
		return textSection;
	}

	private IImageObject convert(IImageObject previewImage) {
		if (previewImage==null){
			return null;
		}
		if (previewImage instanceof LinkImageObject) {
			LinkImageObject m = (LinkImageObject) previewImage;
			return m;
		}
		
		byte[] bytes = previewImage.getBytes(-1,-1);
		return new ByteImageObject(bytes);
	}
	
	public static class ByteImageObject implements IImageObject,Serializable{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		byte[]contents;
		
		public ByteImageObject(byte[] contents) {
			super();
			this.contents = contents;
		}
		protected ByteImageObject(){
			
		}

		@Override
		public byte[] getBytes(int width, int height) {
			return null;
		}

		@Override
		public String getUrl(int width, int height) {
			return "";
		}

		@Override
		public String getCaption() {
			return "";
		}
		
	}

	private IImageObject[] convert(IImageObject[] galleryImages) {
		ArrayList<IImageObject> imgs = new ArrayList<IImageObject>();
		for (IImageObject o : galleryImages) {
			IImageObject convert = convert(o);
			if (convert != null) {
				imgs.add(convert);
			}
		}
		return imgs.toArray(new IImageObject[imgs.size()]);
	}

	@Override
	public IPropertyProvider getPropertyProvider() {
		return this;
	}

	@Override
	public String getUID() {
		return caption.replace('/', '-');
	}

	@Override
	public String getCaption() {
		return caption;
	}

	@Override
	public <C> Collection<ITypedReference<C>> getRelated(Class<C> c) {
		return null;
	}

	@Override
	public boolean hasImage() {
		return images != null && images.length > 0;
	}

	@Override
	public IImageObject[] getGalleryImages() {
		return images;
	}

	@Override
	public IImageObject getPrimaryImage() {
		if (images == null || images.length == 0) {
			return null;
		}
		return images[0];
	}

	@Override
	public IImageObject getPreviewImage() {
		return preview;
	}

	@Override
	public IDataPropertyValue[] getProperties() {
		return accessor.values.values().toArray(new IDataPropertyValue[accessor.values.size()]);
	}

	@Override
	public ITextSection getTextDescription() {
		return new TextSectionModel(textSection, 0);
	}

	@Override
	public boolean hasVideos() {
		return true;
	}

	@Override
	public IVideoObject[] getVideos() {
		ArrayList<IVideoObject> build = YoutubeFeed.build(getCaption());
		return build.toArray(new IVideoObject[build.size()]);
	}

	@Override
	public boolean isPrimaryObject() {
		return primary;
	}
	
	
	public void setPrimaryObject(boolean p) {
		this.primary=p;
	}

	@Override
	public IProperty getProperty(Object obj, String name) {
		for (IDataPropertyValue p : accessor.values.values()) {
			if (p==null){
				continue;
			}
			IDataProperty property = p.getProperty();
			if (property!=null&&property.getId().equals(name)) {
				return property;
			}
		}
		return null;
	}

	@SuppressWarnings({ })
	@Override
	public Iterable<IProperty> getProperties(Object obj) {
		ArrayList<IProperty>pm=new ArrayList<IProperty>();
		for (IDataPropertyValue p : accessor.values.values()) {
			pm.add(p.getProperty());
		}
		return pm;
	}
	

	public byte[] toByteArray(){
		try{
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		GZIPOutputStream gg=new GZIPOutputStream(byteArrayOutputStream);
		Hessian2Output o=new Hessian2Output(gg);
		o.writeObject(this);
		o.close();
		gg.close();
		return byteArrayOutputStream.toByteArray();
		}catch (Exception e) {
			throw new IllegalStateException();
		}
	}

	public void setProperty(AbstractDataProperty p, Object value) {
		IProperty property = getProperty(this, p.getId());
		if (property!=null){
			PropertyAccess.setValue(property, this, value);
		}
		else{
			IDataProperty clone =p.clone(accessor);		
			accessor.setValue(this, (AbstractDataProperty) clone, null);
			PropertyAccess.setValue(clone, this, value);
		}
	}
}